1 : <?php
2 :
3 : /**
4 : * Smarty Internal Plugin Smarty Template Compiler Base
5 : *
6 : * This file contains the basic classes and methods for compiling Smarty templates with lexer/parser
7 : *
8 : *
9 : * @package Compiler
10 : * @author Uwe Tews
11 : */
12 :
13 : /**
14 : * Main abstract compiler class
15 : *
16 : *
17 : * @package Compiler
18 : */
19 : class Smarty_Compiler_Template_Compiler extends Smarty_Compiler
20 1 : {
21 :
22 : /**
23 : * current template
24 : *
25 : * @var Smarty
26 : */
27 : public $tpl_obj = null;
28 :
29 : /**
30 : * source object
31 : *
32 1 : * @var Smarty_Resource
33 : */
34 : public $source = null;
35 :
36 : /**
37 : * Lexer class name
38 : *
39 : * @var string
40 : */
41 : public $lexer_class = '';
42 :
43 : /**
44 : * Flag if caching enabled
45 : * @var boolean
46 : */
47 1 : public $caching = false;
48 :
49 : /**
50 : * Parser class name
51 : *
52 : * @var string
53 : */
54 : public $parser_class = '';
55 :
56 : /**
57 : * Lexer object
58 : *
59 : * @var object
60 : */
61 : public $lex = null;
62 :
63 : /**
64 : * Parser object
65 : *
66 : * @var object
67 : */
68 : public $parser = null;
69 :
70 : /**
71 : * line offset to start of template source
72 : *
73 5 : * @var int
74 : */
75 : public $line_offset = 0;
76 :
77 : /**
78 5 : * inline template code templates
79 : *
80 : * @var array
81 : */
82 : public static $merged_inline_content_classes = array();
83 :
84 : /**
85 : * flag for nocache section
86 : *
87 : * @var bool
88 : */
89 9 : public $nocache = false;
90 :
91 1 : /**
92 : * flag for nocache tag
93 : *
94 : * @var bool
95 : */
96 : public $tag_nocache = false;
97 :
98 : /**
99 : * flag for nocache code not setting $has_nocache_flag
100 : *
101 : * @var bool
102 : */
103 : public $nocache_nolog = false;
104 :
105 : /**
106 : * suppress generation of nocache code
107 : *
108 : * @var bool
109 : */
110 : public $suppressNocacheProcessing = false;
111 :
112 : /**
113 : * flag when compiling inheritance
114 : *
115 30 : * @var bool
116 : */
117 : public $isInheritance = false;
118 2 :
119 2 : /**
120 : * flag when compiling inheritance
121 : *
122 : * @var bool
123 : */
124 : public $isInheritanceChild = false;
125 :
126 : /**
127 : * force compilation of complete template as nocache
128 : * 0 = off
129 : * 1 = observe nocache flags on template type recompiled
130 : * 2 = force all code to be nocache
131 : *
132 : * @var integer
133 : */
134 : public $forceNocache = 0;
135 :
136 : /**
137 : * compile tag objects
138 : *
139 : * @var array
140 : */
141 : public static $_tag_objects = array();
142 :
143 : /**
144 : * tag stack
145 : *
146 : * @var array
147 27 : */
148 : public $_tag_stack = array();
149 :
150 : /**
151 : * file dependencies
152 : *
153 : * @var array
154 : */
155 : public $file_dependency = array();
156 8 :
157 : /**
158 : * template function properties
159 : *
160 : * @var array
161 : */
162 : public $template_functions = array();
163 :
164 : /**
165 : * template function compiled code
166 : *
167 : * @var array
168 : */
169 : public $template_functions_code = array();
170 :
171 : /**
172 : * block function properties
173 : *
174 : * @var array
175 : */
176 : public $inheritance_blocks = array();
177 :
178 : /**
179 : * block function compiled code
180 : *
181 : * @var array
182 : */
183 : public $inheritance_blocks_code = array();
184 :
185 : /**
186 : * block name index
187 : *
188 : * @var integer
189 : */
190 : public $block_name_index = 0;
191 :
192 : /**
193 : * inheritance block nesting level
194 : *
195 : * @var integer
196 : */
197 : public $block_nesting_level = 0;
198 :
199 : /**
200 : * block nesting info
201 : *
202 : * @var array
203 : */
204 : public $block_nesting_info = array();
205 :
206 : /**
207 : * compiled footer code
208 : *
209 : * @var array
210 : */
211 : public $compiled_footer_code = null;
212 :
213 : /**
214 :
215 : /**
216 : * plugins loaded by default plugin handler
217 : *
218 : * @var array
219 : */
220 : public $default_handler_plugins = array();
221 :
222 : /**
223 : * saved preprocessed modifier list
224 : *
225 : * @var mixed
226 : */
227 : public $default_modifier_list = null;
228 :
229 : /**
230 : * suppress template property header code in compiled template
231 : * @var bool
232 : */
233 : public $suppressTemplatePropertyHeader = false;
234 :
235 : /**
236 : * suppress processing of post filter
237 : * @var bool
238 : */
239 : public $suppressPostFilter = false;
240 :
241 : /**
242 : * flag if compiled template file shall we written
243 : * @var bool
244 : */
245 : public $write_compiled_code = true;
246 :
247 : /**
248 : * flag if template does contain nocache code sections
249 : * @var boolean
250 : */
251 : public $has_nocache_code = false;
252 :
253 : /**
254 : * flag if currently a template function is compiled
255 : * @var bool
256 : */
257 : public $compiles_template_function = false;
258 :
259 : /**
260 : * called subfuntions from template function
261 : * @var array
262 : */
263 : public $called_template_functions = array();
264 :
265 : /**
266 : * template functions called nocache
267 : * @var array
268 : */
269 : public $called_nocache_template_functions = array();
270 :
271 : /**
272 : * content class name
273 : * @var string
274 : */
275 : public $content_class = '';
276 :
277 : /**
278 : * required plugins
279 : * @var array
280 : * @internal
281 : */
282 : public $required_plugins = array('compiled' => array(), 'nocache' => array());
283 :
284 : /**
285 : * flags for used modifier plugins
286 : * @var array
287 : */
288 : public $modifier_plugins = array();
289 :
290 : /**
291 : * type of already compiled modifier
292 : * @var array
293 : */
294 : public $known_modifier_type = array();
295 :
296 : /**
297 : * Code object for generated template code
298 : * @var Smarty_Compiler_Code
299 : */
300 : public $template_code = null;
301 :
302 : // TODO check this solution
303 : public $prefix_code = array();
304 : public $postfix_code = array();
305 : public $has_code = false;
306 : public $has_output = false;
307 :
308 : /**
309 : * Initialize compiler
310 : *
311 : * @param string $lexer_class class name
312 : * @param string $parser_class class name
313 : * @param Smarty_Resource $source
314 : * @param boolean $caching flag if caching enabled
315 : * @param Smarty $tpl_obj
316 : */
317 : public function __construct($lexer_class, $parser_class, $tpl_obj, $source, $caching)
318 : {
319 : //parent::__construct();
320 :
321 905 : $this->tpl_obj = $tpl_obj;
322 905 : $this->source = $source;
323 905 : $this->caching = $caching;
324 : // get required plugins
325 905 : $this->lexer_class = $lexer_class;
326 905 : $this->parser_class = $parser_class;
327 : // init code buffer
328 905 : $this->template_code = new Smarty_Compiler_Code(3);
329 905 : $this->template_code->addSourceLineNo(1);
330 :
331 905 : }
332 :
333 : /**
334 : * Method to compile a Smarty template
335 : *
336 : * @param mixed $_content template source
337 : * @return bool true if compiling succeeded, false if it failed
338 : */
339 :
340 : /**
341 : * Method to compile a Smarty template
342 : *
343 : * @param mixed $_content template source
344 : * @return bool true if compiling succeeded, false if it failed
345 : */
346 : protected function doCompile($_content = null)
347 : {
348 : /* here is where the compiling takes place. Smarty
349 : tags in the templates are replaces with PHP code,
350 : then written to compiled files. */
351 :
352 896 : if ($this->tpl_obj->_parserdebug)
353 896 : $this->parser->PrintTrace();
354 : // get tokens from lexer and parse them
355 896 : while ($this->lex->yylex()) {
356 895 : if ($this->tpl_obj->_parserdebug) {
357 0 : echo "<pre>Line {$this->lex->line} Parsing {$this->parser->yyTokenName[$this->lex->token]} Token " .
358 0 : htmlentities($this->lex->value) . "</pre>";
359 0 : }
360 895 : $this->parser->doParse($this->lex->token, $this->lex->value);
361 895 : }
362 :
363 : // finish parsing process
364 854 : $this->parser->doParse(0, 0);
365 : // check for unclosed tags
366 837 : if (count($this->_tag_stack) > 0) {
367 : // get stacked info
368 1 : list($openTag, $_data) = array_pop($this->_tag_stack);
369 1 : $this->trigger_template_error("unclosed {" . $openTag . "} tag");
370 0 : }
371 : // return compiled code
372 : // return str_replace(array("? >\n<?php","? ><?php"), array('',''), $this->parser->retvalue);
373 836 : return $this->parser->retvalue;
374 : }
375 :
376 : /**
377 : * Compiles the template source
378 : *
379 : * If the template is not evaluated the compiled template is saved on disk
380 : *
381 : * @throws Smarty_Exception in case of compilation errors
382 : * @throws Exception
383 : */
384 : public function compileTemplateSource(Smarty_Compiled_Resource $compiled)
385 : {
386 180 : $this->isInheritance = $this->isInheritanceChild = $this->tpl_obj->is_inheritance_child;
387 180 : if (!$this->source->recompiled) {
388 180 : if ($this->source->components) {
389 : // uses real resource for file dependency
390 10 : $source = end($this->source->components);
391 10 : } else {
392 171 : $source = $this->source;
393 : }
394 180 : $this->file_dependency[$this->source->uid] = array($this->source->filepath, $this->source->timestamp, $source->type);
395 180 : }
396 180 : if ($this->tpl_obj->debugging) {
397 0 : Smarty_Debug::start_compile($this->tpl_obj);
398 0 : }
399 : // compile locking
400 180 : if ($this->tpl_obj->compile_locking && !$this->source->recompiled) {
401 180 : if ($saved_timestamp = $compiled->timestamp) {
402 17 : touch($compiled->filepath);
403 17 : }
404 180 : }
405 : // call compiler
406 : try {
407 180 : $code = $this->compileTemplate();
408 180 : } catch (Exception $e) {
409 : // restore old timestamp in case of error
410 42 : if ($this->tpl_obj->compile_locking && !$this->source->recompiled && $saved_timestamp) {
411 0 : touch($compiled->filepath, $saved_timestamp);
412 0 : }
413 42 : throw $e;
414 : }
415 : // compiling succeded
416 140 : if (!$this->source->recompiled && $this->write_compiled_code) {
417 : // write compiled template
418 140 : $_filepath = $compiled->filepath;
419 140 : if ($_filepath === false)
420 140 : throw new Smarty_Exception('Invalid filepath for compiled template');
421 140 : Smarty_Misc_WriteFile::writeFile($_filepath, $code, $this->tpl_obj);
422 140 : $compiled->exists = true;
423 140 : $compiled->isCompiled = true;
424 140 : }
425 140 : if ($this->tpl_obj->debugging) {
426 0 : Smarty_Debug::end_compile($this->tpl_obj);
427 0 : }
428 140 : }
429 :
430 : /**
431 : * Method to compile a Smarty template
432 : *
433 : * @return bool true if compiling succeeded, false if it failed
434 : */
435 : public function compileTemplate()
436 : {
437 : // flag for nochache sections
438 : // $this->nocache = false;
439 905 : $this->tag_nocache = false;
440 : // reset has nocache code flag
441 905 : $this->has_nocache_code = false;
442 : // check if content class name already predefine
443 905 : if (empty($this->content_class)) {
444 905 : $this->content_class = '_SmartyTemplate_' . str_replace('.', '_', uniqid('', true));
445 905 : }
446 905 : $this->tpl_obj->_current_file = $saved_filepath = $this->source->filepath;
447 :
448 : // make sure that we don't run into backtrack limit errors
449 905 : ini_set('pcre.backtrack_limit', -1);
450 : // init the lexer/parser to compile the template
451 905 : $this->lex = new $this->lexer_class(null, $this);
452 905 : $this->parser = new $this->parser_class($this->lex, $this);
453 :
454 :
455 : // get source and run prefilter if required and pass iit to lexer
456 905 : if (isset($this->tpl_obj->autoload_filters['pre']) || isset($this->tpl_obj->registered_filters['pre'])) {
457 4 : $this->lex->data = Smarty_Misc_FilterHandler::runFilter('pre', $this->source->content, $this->tpl_obj);
458 4 : } else {
459 901 : $this->lex->data = $this->source->getContent();
460 : }
461 : // call compiler
462 896 : $this->doCompile();
463 :
464 836 : $this->source->filepath = $saved_filepath;
465 : // free memory
466 836 : $this->parser->compiler = null;
467 836 : $this->parser = null;
468 836 : $this->lex->compiler = null;
469 836 : $this->lex = null;
470 836 : self::$_tag_objects = array();
471 : // return compiled code to template object
472 : // run postfilter if required on compiled template code
473 836 : if (!$this->suppressPostFilter && (isset($this->tpl_obj->autoload_filters['post']) || isset($this->tpl_obj->registered_filters['post']))) {
474 3 : $this->template_code->buffer = Smarty_Misc_FilterHandler::runFilter('post', $this->template_code->buffer, $this->tpl_obj);
475 3 : }
476 836 : if (!$this->suppressTemplatePropertyHeader) {
477 836 : $this->content_class = '_SmartyTemplate_' . str_replace('.', '_', uniqid('', true));
478 836 : $this->template_code = $this->_createSmartyContentClass($this->tpl_obj);
479 813 : }
480 :
481 813 : return $this->template_code->buffer;
482 : }
483 :
484 : /**
485 : * Compile Tag
486 : *
487 : * This is a call back from the lexer/parser
488 : * It executes the required compile plugin for the Smarty tag
489 : *
490 : * @param string $tag tag name
491 : * @param array $args array with tag attributes
492 : * @param array $parameter array with compilation parameter
493 : * @return string compiled code
494 : */
495 : public function compileTag($tag, $args, $parameter = array())
496 : {
497 : // $args contains the attributes parsed and compiled by the lexer/parser
498 : // assume that tag does compile into code, but creates no HTML output
499 807 : $this->has_code = true;
500 807 : $this->has_output = false;
501 : // log tag/attributes
502 807 : if (isset($this->tpl_obj->get_used_tags) && $this->tpl_obj->get_used_tags) {
503 0 : $this->tpl_obj->used_tags[] = array($tag, $args);
504 0 : }
505 : // check nocache option flag
506 807 : if (in_array("'nocache'", $args) || in_array(array('nocache' => 'true'), $args)
507 807 : || in_array(array('nocache' => '"true"'), $args) || in_array(array('nocache' => "'true'"), $args)
508 807 : ) {
509 9 : $this->tag_nocache = true;
510 9 : }
511 : // compile the smarty tag (required compile classes to compile the tag are autoloaded)
512 807 : if (($_output = $this->compileCoreTag($tag, $args, $parameter)) === false) {
513 217 : if (isset($this->template_functions[$tag])) {
514 : // template defined by {template} tag
515 0 : $args['_attr']['name'] = "'" . $tag . "'";
516 0 : $_output = $this->compileCoreTag('Call', $args, $parameter);
517 0 : }
518 217 : }
519 795 : if ($_output !== false) {
520 617 : if ($_output !== true) {
521 : // did we get compiled code
522 615 : if ($this->has_code) {
523 : // return compiled code
524 615 : return $_output;
525 : }
526 0 : }
527 : // tag did not produce compiled code
528 48 : return '';
529 : } else {
530 : // map_named attributes
531 217 : if (isset($args['_attr'])) {
532 0 : foreach ($args['_attr'] as $attribute) {
533 0 : if (is_array($attribute)) {
534 0 : $args = array_merge($args, $attribute);
535 0 : }
536 0 : }
537 0 : }
538 : // not an internal compiler tag
539 217 : if (strlen($tag) < 6 || substr($tag, -5) != 'close') {
540 : // check if tag is a registered object
541 217 : if (isset($this->tpl_obj->registered_objects[$tag]) && isset($parameter['object_method'])) {
542 5 : $method = $parameter['object_method'];
543 5 : if (!in_array($method, $this->tpl_obj->registered_objects[$tag][3]) &&
544 2 : (empty($this->tpl_obj->registered_objects[$tag][1]) || in_array($method, $this->tpl_obj->registered_objects[$tag][1]))
545 5 : ) {
546 2 : return $this->compileCoreTag('Internal_ObjectFunction', $args, $parameter, $tag, $method);
547 3 : } elseif (in_array($method, $this->tpl_obj->registered_objects[$tag][3])) {
548 3 : return $this->compileCoreTag('Internal_ObjectBlockFunction', $args, $parameter, $tag, $method);
549 : } else {
550 0 : $this->trigger_template_error('unallowed method "' . $method . '" in registered object "' . $tag . '"', $this->lex->taglineno);
551 : }
552 0 : }
553 : // check if tag is registered
554 212 : foreach (array(Smarty::PLUGIN_COMPILER, Smarty::PLUGIN_FUNCTION, Smarty::PLUGIN_BLOCK) as $plugin_type) {
555 212 : if (isset($this->tpl_obj->registered_plugins[$plugin_type][$tag])) {
556 : // if compiler function plugin call it now
557 43 : if ($plugin_type == Smarty::PLUGIN_COMPILER) {
558 5 : return $this->compileCoreTag('Internal_PluginCompiler', $args, $parameter, $tag);
559 : }
560 : // compile registered function or block function
561 38 : if ($plugin_type == Smarty::PLUGIN_FUNCTION || $plugin_type == Smarty::PLUGIN_BLOCK) {
562 38 : return $this->compileCoreTag('Internal_Registered' . ucfirst($plugin_type), $args, $parameter, $tag);
563 : }
564 0 : }
565 207 : }
566 : // check plugins from plugins folder
567 169 : foreach ($this->tpl_obj->plugin_search_order as $plugin_type) {
568 169 : if ($plugin_type == Smarty::PLUGIN_COMPILER && $this->tpl_obj->_loadPlugin('smarty_compiler_' . $tag) && (!isset($this->tpl_obj->security_policy) || $this->tpl_obj->security_policy->isTrustedTag($tag, $this))) {
569 1 : $plugin = 'smarty_compiler_' . $tag;
570 1 : if (is_callable($plugin) || class_exists($plugin, false)) {
571 1 : return $this->compileCoreTag('Internal_PluginCompiler', $args, $parameter, $tag);
572 : }
573 0 : $this->trigger_template_error("Plugin '{{$tag}...}' not callable", $this->lex->taglineno);
574 0 : } else {
575 169 : if ($function = $this->getPlugin($tag, $plugin_type)) {
576 139 : if (!isset($this->tpl_obj->security_policy) || $this->tpl_obj->security_policy->isTrustedTag($tag, $this)) {
577 139 : return $this->compileCoreTag('Internal_Plugin'. ucfirst($plugin_type), $args, $parameter, $tag, $function);
578 : }
579 0 : }
580 : }
581 51 : }
582 29 : if (is_callable($this->tpl_obj->default_plugin_handler_func)) {
583 6 : $found = false;
584 : // look for already resolved tags
585 6 : foreach ($this->tpl_obj->plugin_search_order as $plugin_type) {
586 6 : if (isset($this->default_handler_plugins[$plugin_type][$tag])) {
587 0 : $found = true;
588 0 : break;
589 : }
590 6 : }
591 6 : if (!$found) {
592 : // call default handler
593 6 : foreach ($this->tpl_obj->plugin_search_order as $plugin_type) {
594 6 : if ($this->getPluginFromDefaultHandler($tag, $plugin_type)) {
595 6 : $found = true;
596 6 : break;
597 : }
598 6 : }
599 6 : }
600 6 : if ($found) {
601 : // if compiler function plugin call it now
602 6 : if ($plugin_type == Smarty::PLUGIN_COMPILER) {
603 1 : return $this->compileCoreTag('Internal_PluginCompiler', $args, $parameter, $tag);
604 : } else {
605 5 : return $this->compileCoreTag('Internal_Registered' . ucfirst($plugin_type), $args, $parameter, $tag);
606 : }
607 : }
608 0 : }
609 23 : } else {
610 : // compile closing tag of block function
611 46 : $base_tag = substr($tag, 0, -5);
612 : // check if closing tag is a registered object
613 46 : if (isset($this->tpl_obj->registered_objects[$base_tag]) && isset($parameter['object_method'])) {
614 3 : $method = $parameter['object_method'];
615 3 : if (in_array($method, $this->tpl_obj->registered_objects[$base_tag][3])) {
616 3 : return $this->compileCoreTag('Internal_ObjectBlockFunction', $args, $parameter, $tag, $method);
617 : } else {
618 0 : $this->trigger_template_error('unallowed closing tag method "' . $method . '" in registered object "' . $base_tag . '"', $this->lex->taglineno);
619 : }
620 0 : }
621 : // registered compiler plugin ?
622 43 : if (isset($this->tpl_obj->registered_plugins[Smarty::PLUGIN_COMPILER][$tag])) {
623 1 : return $this->compileCoreTag('Internal_PluginCompilerclose', $args, $parameter, $tag);
624 : }
625 : // registered block tag ?
626 42 : if (isset($this->tpl_obj->registered_plugins[Smarty::PLUGIN_BLOCK][$base_tag]) || isset($this->default_handler_plugins[Smarty::PLUGIN_BLOCK][$base_tag])) {
627 20 : return $this->compileCoreTag('Internal_RegisteredBlock', $args, $parameter, $tag);
628 : }
629 : // block plugin?
630 22 : if ($function = $this->getPlugin($base_tag, Smarty::PLUGIN_BLOCK)) {
631 21 : return $this->compileCoreTag('Internal_PluginBlock', $args, $parameter, $tag, $function);
632 : }
633 1 : if ($this->tpl_obj->_loadPlugin('smarty_compiler_' . $tag)) {
634 1 : return $this->compileCoreTag('Internal_PluginCompilerclose', $args, $parameter, $tag);
635 : }
636 0 : $this->trigger_template_error("Plugin '{{$tag}...}' not callable", $this->lex->taglineno);
637 : }
638 23 : $this->trigger_template_error("unknown tag '{{$tag}...}'", $this->lex->taglineno);
639 : }
640 0 : }
641 :
642 : /**
643 : * lazy loads internal compile plugin for tag and calls the compile method
644 : *
645 : * compile objects cached for reuse.
646 : * class name format: Smarty_Compiler_Template_Tag_TagName
647 : *
648 : * @param string $tag tag name
649 : * @param array $args list of tag attributes
650 : * @param mixed $param1 optional parameter
651 : * @param mixed $param2 optional parameter
652 : * @param mixed $param3 optional parameter
653 : * @return string compiled code
654 : */
655 : public function compileCoreTag($tag, $args, $param1 = null, $param2 = null, $param3 = null)
656 : {
657 : // re-use object if already exists
658 807 : if (isset(self::$_tag_objects[$tag])) {
659 : // compile this tag
660 179 : return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3);
661 : }
662 : // check if tag allowed by security
663 794 : if (!isset($this->tpl_obj->security_policy) || $this->tpl_obj->security_policy->isTrustedTag($tag, $this)) {
664 794 : $class = 'Smarty_Compiler_Template_Tag_' . $tag;
665 794 : if (!class_exists($class, false)) {
666 240 : if (is_file($file = SMARTY_DIR . str_replace(array('_', "\0"), array('/', ''), $class) . '.php')) {
667 31 : require $file;
668 31 : } else {
669 217 : return false;
670 : }
671 31 : }
672 769 : self::$_tag_objects[$tag] = new $class;
673 : // compile this tag
674 769 : return self::$_tag_objects[$tag]->compile($args, $this, $param1, $param2, $param3);
675 : }
676 : // no internal compile plugin for this tag
677 0 : return false;
678 : }
679 :
680 : /**
681 : * Compile code for template variable
682 : *
683 : * @param string $variable name of variable
684 : * @return string code
685 : */
686 : public function compileVariable($variable) {
687 360 : if (strpos($variable,'(') === false) {
688 : // not a variable variable
689 360 : $var = trim($variable,'\'"');
690 360 : $this->tag_nocache=$this->tag_nocache|$this->tpl_obj->getVariable($var, null, true, false, 'nocache');
691 : // $this->compiler->tpl_obj->properties['variables'][$var] = $this->compiler->tag_nocache|$this->compiler->nocache;
692 360 : } else {
693 5 : $var = '{'.$variable.'}';
694 : }
695 360 : return '$_scope->'. $var . '->value';
696 : }
697 :
698 : /**
699 : * Check for plugins and return function name
700 : *
701 : * @param string $plugin_name name of plugin or function
702 : * @param string $plugin_type type of plugin
703 : * @return string call name of function
704 : */
705 : public function getPlugin($plugin_name, $plugin_type)
706 : {
707 236 : $function = null;
708 236 : if ($this->caching && ($this->nocache || $this->tag_nocache)) {
709 5 : if (isset($this->required_plugins['nocache'][$plugin_name][$plugin_type])) {
710 0 : $function = $this->required_plugins['nocache'][$plugin_name][$plugin_type]['function'];
711 5 : } elseif (isset($this->required_plugins['compiled'][$plugin_name][$plugin_type])) {
712 0 : $this->required_plugins['nocache'][$plugin_name][$plugin_type] = $this->required_plugins['compiled'][$plugin_name][$plugin_type];
713 0 : $function = $this->required_plugins['nocache'][$plugin_name][$plugin_type]['function'];
714 0 : }
715 5 : } else {
716 231 : if (isset($this->required_plugins['compiled'][$plugin_name][$plugin_type])) {
717 28 : $function = $this->required_plugins['compiled'][$plugin_name][$plugin_type]['function'];
718 231 : } elseif (isset($this->required_plugins['nocache'][$plugin_name][$plugin_type])) {
719 0 : $this->required_plugins['compiled'][$plugin_name][$plugin_type] = $this->required_plugins['nocache'][$plugin_name][$plugin_type];
720 0 : $function = $this->required_plugins['compiled'][$plugin_name][$plugin_type]['function'];
721 0 : }
722 : }
723 236 : if (isset($function)) {
724 28 : if ($plugin_type == 'modifier') {
725 1 : $this->modifier_plugins[$plugin_name] = true;
726 1 : }
727 :
728 28 : return $function;
729 : }
730 : // loop through plugin dirs and find the plugin
731 236 : $function = 'smarty_' . $plugin_type . '_' . $plugin_name;
732 236 : $file = $this->tpl_obj->_loadPlugin($function, false);
733 :
734 236 : if (is_string($file)) {
735 185 : if ($this->caching && ($this->nocache || $this->tag_nocache)) {
736 3 : $this->required_plugins['nocache'][$plugin_name][$plugin_type]['file'] = $file;
737 3 : $this->required_plugins['nocache'][$plugin_name][$plugin_type]['function'] = $function;
738 3 : } else {
739 182 : $this->required_plugins['compiled'][$plugin_name][$plugin_type]['file'] = $file;
740 182 : $this->required_plugins['compiled'][$plugin_name][$plugin_type]['function'] = $function;
741 : }
742 185 : if ($plugin_type == 'modifier') {
743 43 : $this->modifier_plugins[$plugin_name] = true;
744 43 : }
745 :
746 185 : return $function;
747 : }
748 75 : if (is_callable($function)) {
749 : // plugin function is defined in the script
750 0 : return $function;
751 : }
752 :
753 75 : return false;
754 : }
755 :
756 : /**
757 : * Check for plugins by default plugin handler
758 : *
759 : * @param string $tag name of tag
760 : * @param string $plugin_type type of plugin
761 : * @return boolean true if found
762 : */
763 : public function getPluginFromDefaultHandler($tag, $plugin_type)
764 : {
765 10 : $callback = null;
766 10 : $script = null;
767 10 : $cacheable = true;
768 10 : $result = call_user_func_array(
769 10 : $this->tpl_obj->default_plugin_handler_func, array($tag, $plugin_type, $this->tpl_obj, &$callback, &$script, &$cacheable)
770 10 : );
771 10 : if ($result) {
772 10 : $this->tag_nocache = $this->tag_nocache || !$cacheable;
773 10 : if ($script !== null) {
774 8 : if (is_file($script)) {
775 8 : if ($this->caching && ($this->nocache || $this->tag_nocache)) {
776 4 : $this->required_plugins['nocache'][$tag][$plugin_type]['file'] = $script;
777 4 : $this->required_plugins['nocache'][$tag][$plugin_type]['function'] = $callback;
778 4 : } else {
779 4 : $this->required_plugins['compiled'][$tag][$plugin_type]['file'] = $script;
780 4 : $this->required_plugins['compiled'][$tag][$plugin_type]['function'] = $callback;
781 : }
782 8 : include_once $script;
783 8 : } else {
784 0 : $this->trigger_template_error("Default plugin handler: Returned script file \"{$script}\" for \"{$tag}\" not found");
785 : }
786 8 : }
787 10 : if (!is_string($callback) && !(is_array($callback) && is_string($callback[0]) && is_string($callback[1]))) {
788 0 : $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" must be a static function name or array of class and function name");
789 0 : }
790 10 : if (is_callable($callback)) {
791 10 : $this->default_handler_plugins[$plugin_type][$tag] = array($callback, true, array());
792 :
793 10 : return true;
794 : } else {
795 0 : $this->trigger_template_error("Default plugin handler: Returned callback for \"{$tag}\" not callable");
796 : }
797 0 : }
798 :
799 2 : return false;
800 : }
801 :
802 : /**
803 : * Inject inline code for nocache template sections
804 : *
805 : * This method gets the content of each template element from the parser.
806 : * If the content is compiled code and it should be not cached the code is injected
807 : * into the rendered output.
808 : *
809 : * @param string $tagCode code of template element
810 : * @param boolean $is_code true if content is compiled code
811 : * @return string content
812 : */
813 : public function nocacheCode($tagCode, $is_code)
814 : {
815 : // If the template is not evaluated and we have a nocache section and or a nocache tag
816 768 : if ($is_code && (!empty($this->prefix_code) || !empty($this->postfix_code) || !empty($tagCode->buffer))) {
817 :
818 : // generate replacement code
819 767 : $make_nocache_code = $this->nocache || $this->tag_nocache || $this->forceNocache == 2;
820 767 : if ((!($this->source->recompiled) || $this->forceNocache) && $this->caching && !$this->suppressNocacheProcessing &&
821 25 : ($make_nocache_code || $this->nocache_nolog)
822 767 : ) {
823 21 : if ($make_nocache_code) {
824 21 : $this->has_nocache_code = true;
825 21 : }
826 21 : $code = new Smarty_Compiler_Code();
827 21 : $code->iniTagCode($this);
828 :
829 21 : foreach ($this->prefix_code as $prefix_code) {
830 0 : $code->mergeCode($prefix_code);
831 21 : }
832 21 : $code->mergeCode($tagCode);
833 21 : $this->template_code->php("echo \"/*%%SmartyNocache%%*/" . str_replace(array("^#^", "^##^"), array('"', '$'), addcslashes($code->buffer, "\0\t\"\$\\")) . "/*/%%SmartyNocache%%*/\";\n");
834 21 : foreach ($this->postfix_code as $postfix_code) {
835 0 : $this->template_code->mergeCode($postfix_code);
836 21 : }
837 : // make sure we include modifier plugins for nocache code
838 21 : foreach ($this->modifier_plugins as $plugin_name => $dummy) {
839 0 : if (isset($this->required_plugins['compiled'][$plugin_name]['modifier'])) {
840 0 : $this->required_plugins['nocache'][$plugin_name]['modifier'] = $this->required_plugins['compiled'][$plugin_name]['modifier'];
841 0 : }
842 21 : }
843 21 : } else {
844 758 : foreach ($this->prefix_code as $prefix_code) {
845 12 : $this->template_code->mergeCode($prefix_code);
846 754 : }
847 :
848 754 : $this->template_code->mergeCode($tagCode);
849 :
850 754 : foreach ($this->postfix_code as $postfix_code) {
851 0 : $this->template_code->mergeCode($postfix_code);
852 754 : }
853 : }
854 763 : } else {
855 1 : $this->template_code->mergeCode($tagCode);
856 : }
857 764 : $this->prefix_code = array();
858 764 : $this->postfix_code = array();
859 764 : $this->modifier_plugins = array();
860 764 : $this->suppressNocacheProcessing = false;
861 764 : $this->tag_nocache = false;
862 764 : $this->nocache_nolog = false;
863 :
864 764 : return;
865 : }
866 :
867 : /**
868 : * display compiler error messages without dying
869 : *
870 : * If parameter $args is empty it is a parser detected syntax error.
871 : * In this case the parser is called to obtain information about expected tokens.
872 : *
873 : * If parameter $msg contains a string this is used as error message
874 : *
875 : * @param string $msg individual error message or null
876 : * @param string $line line-number
877 : * @throws Smarty_Exception_Compiler when an unexpected token is found
878 : */
879 : public function trigger_template_error($msg = null, $line = null)
880 : {
881 : // get template source line which has error
882 45 : if (!isset($line)) {
883 5 : $line = $this->lex->line;
884 5 : } else {
885 : /** @var $this TYPE_NAME */
886 40 : $line = $line - $this->line_offset;
887 : }
888 45 : preg_match_all("/\n/", $this->lex->data, $match, PREG_OFFSET_CAPTURE);
889 45 : $start_line = max(1, $line - 2);
890 45 : $end_line = min($line + 2, count($match[0]) + 1);
891 45 : $source = "<br>";
892 45 : for ($i = $start_line; $i <= $end_line; $i++) {
893 45 : $from = 0;
894 45 : $to = 99999999;
895 45 : if (isset($match[0][$i - 2])) {
896 5 : $from = $match[0][$i - 2][1];
897 5 : }
898 45 : if (isset($match[0][$i - 1])) {
899 5 : $to = $match[0][$i - 1][1] - $from;
900 5 : }
901 45 : $substr = substr($this->lex->data, $from, $to);
902 45 : $source .= sprintf('%4d : ', $i + $this->line_offset) . htmlspecialchars(trim(preg_replace('![\t\r\n]+!', ' ', $substr))) . "<br>";
903 45 : }
904 45 : $error_text = "<b>Syntax Error</b> in template <b>'{$this->source->filepath}'</b> on line " . ($line + $this->line_offset) . "<br>{$source}";
905 45 : if (isset($msg)) {
906 : // individual error message
907 45 : $error_text .= "<br><b>{$msg}</b><br>";
908 45 : } else {
909 : // expected token from parser
910 0 : $error_text .= "<br> Unexpected '<b>{$this->lex->value}</b>'";
911 0 : if (count($this->parser->yy_get_expected_tokens($this->parser->yymajor)) <= 4) {
912 0 : foreach ($this->parser->yy_get_expected_tokens($this->parser->yymajor) as $token) {
913 0 : $exp_token = $this->parser->yyTokenName[$token];
914 0 : if (isset($this->lex->smarty_token_names[$exp_token])) {
915 : // token type from lexer
916 0 : $expect[] = "'<b>{$this->lex->smarty_token_names[$exp_token]}</b>'";
917 0 : } else {
918 : // otherwise internal token name
919 0 : $expect[] = $this->parser->yyTokenName[$token];
920 : }
921 0 : }
922 0 : $error_text .= ', expected one of: ' . implode(' , ', $expect) . '<br>';
923 0 : }
924 : }
925 45 : throw new Smarty_Exception_Compiler($error_text);
926 : }
927 :
928 : /**
929 : * Create Smarty content class for compiled template files
930 : *
931 : * @param Smarty $tpl_obj template object
932 : * @param bool $noinstance flag if code for creating instance shall be suppressed
933 : * @return string
934 : */
935 : public function _createSmartyContentClass(Smarty $tpl_obj, $noinstance = false)
936 : {
937 836 : $template_code = new Smarty_Compiler_Code();
938 836 : $template_code->php("<?php /* Smarty version " . Smarty::SMARTY_VERSION . ", created on " . strftime("%Y-%m-%d %H:%M:%S") . " compiled from \"{$this->source->filepath}\" */")->newline();
939 836 : $template_code->php("if (!class_exists('{$this->content_class}',false)) {")->newline()->indent();
940 836 : $template_code->php("class {$this->content_class} extends Smarty_Template_" . ($this->isInheritance ? 'Inheritance' : 'Class') . " {")->newline()->indent();
941 836 : $template_code->php("public \$version = '" . Smarty::SMARTY_VERSION . "';")->newline();
942 836 : $template_code->php("public \$has_nocache_code = " . ($this->has_nocache_code ? 'true' : 'false') . ";")->newline();
943 836 : if ($this->isInheritanceChild) {
944 21 : $template_code->php("public \$is_inheritance_child = true;")->newline();
945 21 : }
946 836 : if (!empty($tpl_obj->cached_subtemplates)) {
947 0 : $template_code->php("public \$cached_subtemplates = ")->repr($tpl_obj->cached_subtemplates, false)->raw(';')->newline();
948 0 : }
949 836 : if (!$noinstance) {
950 836 : $template_code->php("public \$file_dependency = ")->repr($this->file_dependency, false)->raw(';')->newline();
951 836 : }
952 836 : if (!empty($this->required_plugins['compiled'])) {
953 202 : $plugins = array();
954 202 : foreach ($this->required_plugins['compiled'] as $tmp) {
955 202 : foreach ($tmp as $data) {
956 202 : $plugins[$data['file']] = $data['function'];
957 202 : }
958 202 : }
959 202 : $template_code->php("public \$required_plugins = ")->repr($plugins, false)->raw(';')->newline();
960 202 : }
961 :
962 836 : if (!empty($this->required_plugins['nocache'])) {
963 7 : $plugins = array();
964 7 : foreach ($this->required_plugins['nocache'] as $tmp) {
965 7 : foreach ($tmp as $data) {
966 7 : $plugins[$data['file']] = $data['function'];
967 7 : }
968 7 : }
969 7 : $template_code->php("public \$required_plugins_nocache = ")->repr($plugins, false)->raw(';')->newline();
970 7 : }
971 :
972 836 : if (!empty($this->template_functions)) {
973 8 : $template_code->php("public \$template_functions = ")->repr($this->template_functions, false)->raw(';')->newline();
974 8 : }
975 836 : if (!empty($this->inheritance_blocks)) {
976 25 : $template_code->php("public \$inheritance_blocks = ")->repr($this->inheritance_blocks, false)->raw(';')->newline();
977 25 : }
978 836 : if (!empty($this->called_nocache_template_functions)) {
979 1 : $template_code->php("public \$called_nocache_template_functions = ")->repr($this->called_nocache_template_functions, false)->raw(';')->newline();
980 1 : }
981 836 : $template_code->newline()->newline()->php("function _renderTemplate (\$_smarty_tpl, \$_scope) {")->newline()->indent();
982 836 : $template_code->php("ob_start();")->newline();
983 836 : $template_code->mergeCode($this->template_code);
984 836 : if (!empty($this->compiled_footer_code)) {
985 21 : $template_code->buffer .= implode('', $this->compiled_footer_code);
986 21 : }
987 836 : $template_code->php("return ob_get_clean();")->newline();
988 836 : $template_code->outdent()->php('}')->newline()->newline();
989 836 : foreach ($this->template_functions_code as $code) {
990 8 : $template_code->mergeCode($code)->newline();
991 836 : }
992 836 : foreach ($this->inheritance_blocks_code as $code) {
993 25 : $template_code->mergeCode($code)->newline();
994 813 : }
995 813 : $template_code->php("function _getSourceInfo () {")->newline()->indent();
996 813 : $template_code->php("return ")->repr($template_code->traceback)->raw(";")->newline();
997 813 : $template_code->outdent()->php('}')->newline();
998 :
999 813 : $template_code->outdent()->php('}')->newline()->outdent()->php('}')->newline();
1000 813 : if (!$noinstance) {
1001 813 : foreach (self::$merged_inline_content_classes as $key => $inlinetpl_obj) {
1002 0 : $template_code->newline()->raw($inlinetpl_obj['code']);
1003 0 : unset(self::$merged_inline_content_classes[$key], $inlinetpl_obj);
1004 813 : }
1005 813 : }
1006 813 : if (!$noinstance) {
1007 813 : $template_code->php("\$this->smarty_content = new {$this->content_class}(\$tpl_obj, \$this);")->newline()->newline();
1008 813 : }
1009 :
1010 813 : return $template_code;
1011 : }
1012 :
1013 : }
|